﻿using WPFTrees.Parser;
using WPFTrees.DataStructures;
using System.Windows;
using System.Windows.Shapes;
using System.Windows.Media;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Data;
using Microsoft.Win32;
using System;
namespace WPFTrees
{
    public partial class MainWindow
    {
        // TODO: nekde to pouzij
        Rect ComputeBoundingBox(out double rootOffset)
        { 
            double xMin= double.PositiveInfinity;
            double yMin= _rootPos.Y;
            double xMax= 0.0;
            double yMax= 0.0;

            foreach (Label label in labels)
            {
                UIElement elem = label.Parent as UIElement;                
                xMin = Math.Min(Canvas.GetLeft(elem),xMin);
                xMax = Math.Max(Canvas.GetLeft(elem)+elem.RenderSize.Width, xMax);                
                yMax = Math.Max(Canvas.GetTop(elem)+elem.RenderSize.Height, yMax);                                
            }

            Rect boundingBox = new Rect(0,0,Math.Abs(xMax-xMin),Math.Abs(yMax-yMin));
            rootOffset = _rootPos.X - xMin;
            return boundingBox;
        }

        // umisti panel se stromem do stredu pracovni plochy
        void CenterTree()
        {
            /*
            double rootOffset;
            Rect boundingBox = ComputeBoundingBox(out rootOffset);
            
            double xOff = (canvas.RenderSize.Width - boundingBox.Width) / 2;
            double yOff = (canvas.RenderSize.Height- boundingBox.Height) / 2;
            
            _rootPos = new Point(xOff + rootOffset, yOff);
            RenderTree(tree);
             */
            // centers canvas
            Size parentSize = parentCanvas.RenderSize;
            Point sizePt = new Point(dockPanel.RenderSize.Width, dockPanel.RenderSize.Height);

            double x = Canvas.GetLeft(dockPanel);
            double y = Canvas.GetTop(dockPanel);
            Point newPos = new Point(parentSize.Width / 2 - sizePt.X/ 2,parentSize.Height / 2 - sizePt.Y/ 2);
            
            Canvas.SetLeft(dockPanel, newPos.X);
            Canvas.SetTop(dockPanel, newPos.Y);
        }

        void ComputeLeaves()
        {
            maxDepth = 0;
            ComputeLeavesRecursive(CurrentTree.GetRoot(),ref maxDepth);
            tree.Info.MaxDepth = maxDepth;
            ComputeMaxDepth();
        }

        void ComputeMaxDepth()
        {
            maxDepthInUnits = 0;            
            ComputeMaxBranchDepth(CurrentTree.GetRoot(), 0);
            tree.Info.MaxDepthInUnits = maxDepthInUnits;
        }

        int maxDepth = 0;
        double maxDepthInUnits = 0.0;

        int ComputeLeavesRecursive(NTreeNode<NewickNode> root, ref int level)
        {
            level++;
            int leaves = 0;            
            foreach (NTreeNode<NewickNode> item in root.Children)
            {
                if (item != null)
                {
                    NewickNode node = item.Value();
                    if (node.IsLeaf)
                    {
                        leaves++;                        
                    }
                    else leaves += ComputeLeavesRecursive(item, ref level);                   
                }
            }
            root.Leaves = leaves;
            return leaves;
        }

        void ComputeMaxBranchDepth(NTreeNode<NewickNode> root, double depth)
        {
            if (root.Value().BranchLenght.HasValue)
            {
                depth += root.Value().BranchLenght.Value;
            }
            maxDepthInUnits = Math.Max(maxDepthInUnits,depth);
            foreach (NTreeNode<NewickNode> item in root.Children)
            {
                if (item != null)
                {
                    NewickNode node = item.Value();
            
                    if (node.IsLeaf)
                    {
                        if (node.BranchLenght.HasValue)
                        {
                            maxDepthInUnits = Math.Max(depth + node.BranchLenght.Value, maxDepthInUnits);
                        }
                    }
                    else ComputeMaxBranchDepth(item, depth);
                }
            }
        }

        #region Compute Group Radius
        
        internal static double ComputeGroupRadius(NTreeNode<NewickNode> root, double radius, double unit, bool bUseBranchLenghts)
        {
            double maxRadius = 0.0;
            Point rootPos = new Point(Canvas.GetLeft(root.Value().VisualElement), Canvas.GetTop(root.Value().VisualElement));
            ComputeGroupRadiusRecursive(root,ref maxRadius, rootPos);
            return maxRadius + ((bUseBranchLenghts && root.Value().BranchLenght.HasValue) ? unit * root.Value().BranchLenght.Value : radius);

        }

        static void ComputeGroupRadiusRecursive(NTreeNode<NewickNode> root, ref double max, Point rootPos)
        { 
            //TODO: dokumentace + formatovani
            if(root.Value().IsLeaf)
            {
                Point nodePos = new Point(Canvas.GetLeft(root.Value().VisualElement), Canvas.GetTop(root.Value().VisualElement));            
                max = Math.Max(max, Point.Subtract(nodePos,rootPos).Length);
            }
            for(int i = 0;i<root.CountImmediateChildren;i++)
	        {
		        ComputeGroupRadiusRecursive(root.Children[i], ref max, rootPos);
	        }

        }

        #endregion
    }
}